﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ModBot.ConfigBuilder.Providers
{
    public enum DebuffTargetType
    {
        AllMobs = 0,
        MATargetOnly = 1,
        AllExceptMATarget = 2,
        AllMobsBeforeNextSpell = 10,
        MATargetOnlyBeforeNextSpell = 11,
        AllButMATargetBeforeNextSpell = 12
    }
            

    public class DebuffSettingsProvider
    {
        private ModBotSettingsProvider parentProvider;
        public List<DebuffSettingInstanceProvider> DebuffSettingInstances;

        #region Public Properties

        /// <summary>
        /// Gets the number of debuff options configured
        /// </summary>
        public int ADCount { get; set; }

        /// <summary>
        /// Gets or sets the interval in seconds to check for debuffs.
        /// </summary>
        public int ADCheckTime { get; set; }

        /// <summary>
        /// Gets or sets the size of the array to be used for mob tracking.
        /// The loop to find valid mobs uses SpawnCount, then stores the mobs 
        /// it "finds" in the array. Setting this to 20 or 30 should be 
        /// way more than enough ever. It is best to keep this setting 
        /// (and therefor the array) relative small for memory purposes 
        /// (as well as for speed through the debuff loop)) 
        /// </summary>
        public int ADMobMax { get; set; }
       
        /// <summary>
        /// Gets or sets how mobs are added to the mob list. When true, 
        /// only mobs in your group or in netbots is the mob's target. 
        /// Only use this option on bots that cast on targets that are 
        /// NOT the main assist's target (e.g. chanter mezzing adds).)
        /// ADAggroOnly is not terribly reliable at times. If you are 
        /// having issues with one of your bots auto-aggroing mobs 
        /// (when they are not the tank), try setting ADAggroOnly=0 
        /// and then ADTarType=1 or 11. 
        /// </summary>
        public Boolean ADAggroOnly { get; set; }

        /// <summary>
        /// Gets or sets the timer to hold the bot in the debuff loop until 
        /// the debuff is complete.
        /// Format: 1=on 0=off|Debuff spell #|Time to wait for debuff|
        /// </summary>
        public string ADHold { get; set; }


        #endregion

        private DebuffSettingsProvider() { }
        public DebuffSettingsProvider(ModBotSettingsProvider parentProvider)
        {
            this.parentProvider = parentProvider;
            DebuffSettingInstances = new List<DebuffSettingInstanceProvider>();
        }

        public override string ToString()
        {
            #region Format String
            string formatString =
                "[AdvDebuff]\r\n" +
                "ADCount={0}\r\n" +
                "ADMobMax={1}\r\n" +
                "ADCheckTime={2}\r\n" +
                "ADAggroOnly={3}\r\n" +
                "ADHold={4}\r\n\r\n";


            #endregion


            string output = string.Format(formatString,
                ADCount,
                ADMobMax,
                ADCheckTime,
                ADAggroOnly,
                ADHold);

            foreach (DebuffSettingInstanceProvider provider in this.DebuffSettingInstances)
            {
                output += provider.ToString();
            }


            return output;
        }

        public static DebuffSettingsProvider LoadFromINI(ModBotSettingsProvider settingsProvider, string filepath)
        {
            DebuffSettingsProvider provider = new DebuffSettingsProvider(settingsProvider);

            try
            {
                provider.ADCount = SharedLib.ConvertToInt32(IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffSettings_Key_ADCount), Defaults.Default_DebuffSettings_ADCount);
                provider.ADMobMax = SharedLib.ConvertToInt32(IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffSettings_Key_ADMobMax), Defaults.Default_DebuffSettings_ADMobMax);
                provider.ADCheckTime = SharedLib.ConvertToInt32(IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffSettings_Key_ADCheckTime), Defaults.Default_DebuffSettings_ADCheckTime);
                provider.ADAggroOnly = SharedLib.ConvertToBoolean(IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffSettings_Key_ADAggroOnly), Defaults.Default_DebuffSettings_ADAggroOnly);
                provider.ADHold = IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffSettings_Key_ADHold);
                                
                provider.DebuffSettingInstances.Clear();
                for (int i = 0; i < provider.ADCount; i++)
                {
                    DebuffSettingInstanceProvider instance = DebuffSettingInstanceProvider.LoadFromINI(provider, i + 1, filepath);
                    provider.DebuffSettingInstances.Add(instance);
                }

                if (provider.ADCount != provider.DebuffSettingInstances.Count) provider.ADCount = provider.DebuffSettingInstances.Count;

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            return provider;
        }

        public static void SaveToIni(DebuffSettingsProvider provider, string filepath)
        {
            IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffSettings_Key_ADCount, Convert.ToString(provider.ADCount));
            IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffSettings_Key_ADMobMax, Convert.ToString(provider.ADMobMax));
            IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffSettings_Key_ADCheckTime, Convert.ToString(provider.ADCheckTime));
            
            // Special case here where Boolean translated to 0/1
            if (provider.ADAggroOnly)
            {
                IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffSettings_Key_ADAggroOnly, "1");
            }
            else
            {
                IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffSettings_Key_ADAggroOnly, "0");
            }

            IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffSettings_Key_ADHold, Convert.ToString(provider.ADHold));


            for (int i = 0; i < provider.ADCount; i++)
            {
                DebuffSettingInstanceProvider.SaveToIni(provider.DebuffSettingInstances[i], filepath);
            }
        }
    }

    public class DebuffSettingInstanceProvider
    {
        private DebuffSettingsProvider settingsProvider;
        /// <summary>
        /// Gets or sets the Gem number, alt, ability, item, script, or potionbelt reference to use
        /// for this debuff.
        /// </summary>
        public string ADGem { get; set; }

        /// <summary>
        /// Gets or sets the spell, item, alt, ability, or script name to reference with
        /// this debuff.
        /// </summary>
        public string ADSpell { get; set; }

        /// <summary>
        /// Gets or sets the bandolier set name to swap in before casting the debuff.
        /// Please see MQ2Bandolier and MQ2Cast for more information.
        /// </summary>
        public string ADSpellFoci { get; set; }

        /// <summary>
        /// Gets or sets any spell extension percentage.
        /// </summary>
        public int ADDurMod { get; set; }

        /// <summary>
        /// Gets or sets the alias for the spell being cast. Note this alias
        /// must be unique and cannot contain spaces.
        /// </summary>
        public string ADSpellAlias { get; set; }

        /// <summary>
        /// Gets or sets the channel to announce the debuff or, if left blank
        /// will not announce the debuff.
        /// </summary>
        public string ADAnnouce { get; set; }

        /// <summary>
        /// Gets or sets the minimum mana percentage to have before
        /// attempting the debuff.
        /// </summary>
        public int ADSpellMinMana { get; set; }

        /// <summary>
        /// Gets or sets the number of time to recast the spell 
        /// when a fizzle or interupt is encountered.
        /// </summary>
        public int ADSpellRecast { get; set; }

        /// <summary>
        /// Gets or sets the spell alias to call should this spell
        /// be resisted.
        /// Note ADSpellRecast must be greater than 0 for this setting to perform properly.
        /// </summary>
        public string ADSpellCastonResist { get; set; }

        /// <summary>
        /// Gets or sets the length of time in seconds to wait between
        /// casting this spell.
        /// </summary>
        public int ADSpellDelay { get; set; }

        /// <summary>
        /// Gets or sets the number of targets that must be 
        /// present before casting the spell.
        /// </summary>
        public Int32 ADTarCnt { get; set; }

        /// <summary>
        /// Gets or sets the target type to cast this debuff on.
        /// </summary>
        public DebuffTargetType ADTarType { get; set; }

        /// <summary>
        /// Gets or sets the percentage of hps the target must be
        /// equal to or below for this debuff to cast.
        /// </summary>
        public int ADTarBegHP { get; set; }

        /// <summary>
        /// Gets or sets the percentage of hps the target must be
        /// equal to or above for this debuff to cast.
        /// </summary>
        public int ADTarEndHP { get; set; }

        /// <summary>
        /// Gets or sets a pointer to a single line script that
        /// is executed when the mob is immune to the specified 
        /// debuff.
        /// An example where this would be useful is for enchanter mez: 
        ///	/bc {TankName} //multiline ; /varset ACMATarget {Param1};/target id {Param1} 
        ///	This will make your TankName toon target the immune mob even if he was on another mob at the time. 
        /// </summary>
        public string ADIfSpellImmune { get; set; }

        /// <summary>
        /// Gets or sets the number of seconds to wait between
        /// TargetOfTarget requests on the mob.
        /// </summary>
        public int ADUseHOTT { get; set; }

        /// <summary>
        /// Gets or sets the debuff pre condition.
        /// </summary>
        public Boolean ADPreCondition { get; set; }        

        /// <summary>
        /// Gets or sets the debuff group index.
        /// </summary>
        public int Index { get; set; }

        private DebuffSettingInstanceProvider() { }

        public DebuffSettingInstanceProvider(DebuffSettingsProvider settingsProvider, int index)
        {
            this.settingsProvider = settingsProvider;
            this.Index = index;

            this.ADGem = Defaults.Default_DebuffInstance_ADGem;
           
        }

        public override string ToString()
        {
            #region Format String
            string formatString =
                SharedLib.CreateSubCommentBlock("Debuff Instance " + Index, SharedLib.NewLine, true) +
                  "ADGem{0}={1}\r\n" +
                  "ADSpell{0}={2}\r\n" +
                  "ADSpellFoci{0}={3}\r\n" +
                  "ADDurMod{0}={4}\r\n" +
                  "ADSpellAlias{0}={5}\r\n" +
                  "ADAnnouce{0}={6}\r\n" +
                  "ADSpellMinMana{0}={7}\r\n" +
                  "ADSpellRecast{0}={8}\r\n" +
                  "ADSpellCastonResist{0}={9}\r\n" +
                  "ADSpellDelay{0}={10}\r\n" +
                  "ADTarCnt{0}={11}\r\n" +
                  "ADTarType{0}={12}\r\n" +
                  "ADTarBegHP{0}={13}\r\n" +
                  "ADTarEndHP{0}={14}\r\n" +
                  "ADIfSpellImmune{0}={15}\r\n" +
                  "ADUseHOTT{0}={16}\r\n" +
                  "ADPreCondition{0}={17}\r\n\r\n";

            #endregion


            string output = string.Format(formatString,
                Index,
                ADGem,
                ADSpell,
                ADSpellFoci,
                ADDurMod,
                ADSpellAlias,
                ADAnnouce,
                ADSpellMinMana,
                ADSpellRecast,
                ADSpellCastonResist,
                ADSpellDelay,
                ADTarCnt,
                (int)ADTarType,
                ADTarBegHP,
                ADTarEndHP,
                ADIfSpellImmune,
                ADUseHOTT,
                ADPreCondition);

            return output;
        }

        public static DebuffSettingInstanceProvider LoadFromINI(DebuffSettingsProvider settingsProvider, int index, string filepath)
        {
            DebuffSettingInstanceProvider provider = new DebuffSettingInstanceProvider(settingsProvider, index);

            try
            {
                provider.ADGem = IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADGem + provider.Index);
                provider.ADSpell = IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADSpell + provider.Index);
                provider.ADSpellFoci = IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADSpellFoci + provider.Index);
                provider.ADDurMod = SharedLib.ConvertToInt32(IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADDurMod + provider.Index), Defaults.Default_DebuffInstance_ADDurMod);
                provider.ADSpellAlias = IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADSpellAlias + provider.Index);
                provider.ADAnnouce = IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADAnnouce + provider.Index);
                provider.ADSpellMinMana = SharedLib.ConvertToInt32(IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADSpellMinMana + provider.Index), Defaults.Default_DebuffInstance_ADSpellMinMana);
                provider.ADSpellRecast = SharedLib.ConvertToInt32(IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADSpellRecast + provider.Index), Defaults.Default_DebuffInstance_ADSpellRecast);
                provider.ADSpellCastonResist = IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADSpellCastonResist + provider.Index);
                provider.ADSpellDelay = SharedLib.ConvertToInt32(IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADSpellDelay + provider.Index), Defaults.Default_DebuffInstance_ADSpellDelay);
                provider.ADTarCnt = SharedLib.ConvertToInt32(IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADTarCnt + provider.Index), Defaults.Default_DebuffInstance_ADTarCnt);
                provider.ADTarType = (DebuffTargetType)SharedLib.ConvertToInt32(IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADTarType + provider.Index), (int)Defaults.Default_DebuffInstance_ADTarType);
                provider.ADTarBegHP = SharedLib.ConvertToInt32(IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADTarBegHP + provider.Index), Defaults.Default_DebuffInstance_ADTarBegHP);
                provider.ADTarEndHP = SharedLib.ConvertToInt32(IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADTarEndHP + provider.Index), Defaults.Default_DebuffInstance_ADTarEndHP);
                provider.ADIfSpellImmune = IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADIfSpellImmune + provider.Index);
                provider.ADUseHOTT = SharedLib.ConvertToInt32(IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADUseHOTT + provider.Index), Defaults.Default_DebuffInstance_ADUseHOTT);
                provider.ADPreCondition = SharedLib.ConvertToBoolean(IniFileProvider.ReadValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADPreCondition + provider.Index), Defaults.Default_DebuffInstance_ADPreCondition);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            return provider;
        }

        public static void SaveToIni(DebuffSettingInstanceProvider provider, string filepath)
        {
            IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADGem + provider.Index, Convert.ToString(provider.ADGem));
            IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADSpell + provider.Index, Convert.ToString(provider.ADSpell));
            IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADSpellFoci + provider.Index, Convert.ToString(provider.ADSpellFoci));
            IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADDurMod + provider.Index, Convert.ToString(provider.ADDurMod));
            IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADSpellAlias + provider.Index, Convert.ToString(provider.ADSpellAlias));
            IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADAnnouce + provider.Index, Convert.ToString(provider.ADAnnouce));
            IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADSpellMinMana + provider.Index, Convert.ToString(provider.ADSpellMinMana));
            IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADSpellRecast + provider.Index, Convert.ToString(provider.ADSpellRecast));
            IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADSpellCastonResist + provider.Index, Convert.ToString(provider.ADSpellCastonResist));
            IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADSpellDelay + provider.Index, Convert.ToString(provider.ADSpellDelay));
            IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADTarCnt + provider.Index, Convert.ToString(provider.ADTarCnt));
            IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADTarType + provider.Index, Convert.ToString((int)provider.ADTarType));
            IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADTarBegHP + provider.Index, Convert.ToString(provider.ADTarBegHP));
            IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADTarEndHP + provider.Index, Convert.ToString(provider.ADTarEndHP));
            IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADIfSpellImmune + provider.Index, Convert.ToString(provider.ADIfSpellImmune));
            IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADUseHOTT + provider.Index, Convert.ToString(provider.ADUseHOTT));
            IniFileProvider.WriteValue(filepath, Keys.DebuffSettings_Section_Key, Keys.DebuffInstance_Key_ADPreCondition + provider.Index, Convert.ToString(provider.ADPreCondition));
        }
    }
}
